package com.pxene.dmp.common;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import com.google.gson.Gson;
import com.pxene.dmp.bean.Response;
import com.pxene.dmp.constant.BaseConstant;

public class KVRequester {

	private Log log = LogFactory.getLog(KVRequester.class);
	private BufferedWriter bw;
	private CloseableHttpClient client;
	private HttpGet request;
	private Gson gson = new Gson();

	public KVRequester(String url, Map<String, String> params, BufferedWriter bw) {
		this.client = HttpClients.createDefault();
		this.request = new HttpGet(url);
		this.request.setConfig(RequestConfig.custom().setSocketTimeout(20000).setConnectTimeout(20000).build());
		for (Map.Entry<String, String> entry : params.entrySet()) {
			request.setHeader(entry.getKey(), entry.getValue());
		}
		this.bw = bw;
	}

	public <T extends Response> Response execute(Class<T> type) {
		HttpResponse httpResp = null;
		Response resp = null;
		try {
			httpResp = client.execute(request);
			resp = parseResponse(httpResp.getEntity().getContent(), type);
		} catch (IOException e) {
			log.error(BaseConstant.LOG_PREFIX + "HttpClient Execute Exception:" + getParameters(request), e);
			try {
				StackTraceElement[] traceEle = e.getStackTrace();
				StringBuffer element = new StringBuffer();
				for (int i = 0; i < traceEle.length; i++) {
					element.append("\t" + traceEle[i].getClassName()).append("(").append(traceEle[i].getMethodName())
							.append(":").append(traceEle[i].getLineNumber()).append(")").append("\n");
				}
				bw.write("[ERROR] " + DateUtils.getNowFormat("yyyy-MM-dd HH:mm:ss") + " ["
						+ Thread.currentThread().getName() + "] [" + KVRequester.class.getName() + "] "
						+ "<=ee-debug=>" + "HttpClient Execute Exception:" + getParameters(this.request) + "\n" + e
						+ "\n" + element.toString() + "\n");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		return resp;
	}

	public void close() {
		if (client != null) {
			try {
				client.close();
			} catch (IOException e) {
				log.error(BaseConstant.LOG_PREFIX + "HttpClient Close Exception:" + getParameters(request), e);
				try {
					StackTraceElement[] traceEle = e.getStackTrace();
					StringBuffer element = new StringBuffer();
					for (int i = 0; i < traceEle.length; i++) {
						element.append("\t" + traceEle[i].getClassName()).append("(")
								.append(traceEle[i].getMethodName()).append(":").append(traceEle[i].getLineNumber())
								.append(")").append("\n");
					}
					bw.write("[ERROR] " + DateUtils.getNowFormat("yyyy-MM-dd HH:mm:ss") + " ["
							+ Thread.currentThread().getName() + "] [" + KVRequester.class.getName() + "] "
							+ "<=ee-debug=>" + "HttpClient Close Exception:" + getParameters(this.request) + "\n" + e
							+ "\n" + element.toString() + "\n");
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}
	}

	private <T extends Response> Response parseResponse(InputStream input, Class<T> type) {
		byte[] cache = new byte[1024];
		try {
			input.read(cache);
		} catch (IOException e) {
			log.error(BaseConstant.LOG_PREFIX + "To Object Exception:" + getParameters(request), e);
			try {
				StackTraceElement[] traceEle = e.getStackTrace();
				StringBuffer element = new StringBuffer();
				for (int i = 0; i < traceEle.length; i++) {
					element.append("\t" + traceEle[i].getClassName()).append("(").append(traceEle[i].getMethodName())
							.append(":").append(traceEle[i].getLineNumber()).append(")").append("\n");
				}
				bw.write("[ERROR] " + DateUtils.getNowFormat("yyyy-MM-dd HH:mm:ss") + " ["
						+ Thread.currentThread().getName() + "] [" + KVRequester.class.getName() + "] "
						+ "<=ee-debug=>" + "To Object Exception:" + getParameters(this.request) + "\n" + e + "\n"
						+ element.toString() + "\n");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}

		return gson.fromJson(new String(cache, 0, cache.length).trim(), type);
	}

	private String getParameters(HttpGet request) {
		StringBuilder sb = new StringBuilder();
		for (Header header : request.getAllHeaders()) {
			sb.append(header.getName()).append("=").append(header.getValue()).append(",");
		}
		sb.append("url=").append(request.getURI());

		return sb.toString();
	}
}
